package com.atmosphere.component.base;

import com.atmosphere.interfaces.IComponentKey;
import com.atmosphere.interfaces.component.IAbstractAstronomy;
import com.jme.animation.SpatialTransformer;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Node;

/**
 * <code>AbstractAstronomy</code> defines the implementation of
 * the abstraction of a component unit that involves astronomy
 * motion.
 *
 * @author Yi Wang (Neakor)
 * @version Creation date: 05-20-2009 18:30 EST
 * @version Modified date: 05-20-2009 18:32 EST
 */
public abstract class AbstractAstronomy extends AbstractComponent implements IAbstractAstronomy {
	/**
	 * The astronomy <code>Node</code>.
	 */
	protected final Node node;
	/**
	 * The <code>Vector3f</code> astronomy position.
	 */
	protected Vector3f position;
	/**
	 * The <code>Float</code> rotation length.
	 */
	protected float length;
	/**
	 * The <code>Vector3f</code> rotation axis.
	 */
	protected Vector3f axis;
	/**
	 * The <code>Boolean</code> position property dirty flag.
	 */
	protected boolean positionDirty;
	/**
	 * The <code>Boolean</code> rotation property dirty flag.
	 */
	protected boolean rotationDirty;
	/**
	 * The astronomy <code>SpatialTransformer</code> animator.
	 */
	protected SpatialTransformer animator;
	
	/**
	 * Constructor of <code>AbstractAstronomy</code>.
	 * @param key The <code>IComponentKey</code>.
	 */
	protected AbstractAstronomy(IComponentKey key) {
		super(key);
		this.node = new Node(key.getValue());
		this.node.setLocalTranslation(new Vector3f());
	}
	
	/**
	 * Initialize the rotation motion.
	 */
	protected void initRotation() {
		if(this.length <= 0) return;
		// Normalize axis.
		this.axis.normalizeLocal();
		// Build motion.
		this.animator = new SpatialTransformer(1);
		this.animator.setObject(this.node, 0, -1);
		Quaternion midNight = new Quaternion();
		midNight.fromAngleAxis(0, this.axis);
		this.animator.setRotation(0, 0, midNight);
		Quaternion noon = new Quaternion();
		noon.fromAngleAxis(FastMath.DEG_TO_RAD*180, this.axis);
		this.animator.setRotation(0, this.length/2, noon);
		Quaternion finalMidNight = new Quaternion();
		finalMidNight.fromAngleAxis(FastMath.DEG_TO_RAD*360, this.axis);
		this.animator.setRotation(0, this.length, finalMidNight);
		this.animator.setActive(true);
		this.animator.setRepeatType(Controller.RT_WRAP);
		this.animator.interpolateMissing();
		this.node.addController(this.animator);
		// Flip flag.
		this.rotationDirty = false;
	}

	@Override
	public void setPosition(Vector3f position) {
		this.position = position.clone();
		this.positionDirty = true;
	}

	@Override
	public void setCycleLength(float length) {
		this.length = length;
		this.rotationDirty = true;
	}

	@Override
	public void setRotationAxis(Vector3f axis) {
		this.axis = axis.clone();
		this.rotationDirty = true;
	}

	@Override
	public Vector3f getPosition() {
		return this.position;
	}

	@Override
	public float getCycleLength() {
		return this.length;
	}

	@Override
	public Vector3f getRotationAxis() {
		return this.axis;
	}
}
